﻿=================================Lesson2 整合thymeleaf ====================================
1 整合Thymeleaf
2 Thymeleaf 语法 之th属性
3 Thymeleaf 语法 之常用的内置方法
4 Thymeleaf 语法 之标准表达式语法
5 Thymeleaf在SpringBoot应用
6 增删改查
===========================================================================================
==== 1 整合Thymeleaf			

    Thymeleaf是个  XML/XHTML/HTML5模板引擎，可以用于Web与非Web应用。

　　Thymeleaf的主要目标在于提供一种可被浏览器正确显示的、格式良好的模板创建方式，因此也可以用作静态建模。
			你可以使用它创建经过验证的XML与HTML模板。相对于编写逻辑或代码，开发者只需将标签属性添加到模板中即可。
			接下来，这些标签属性就会在DOM（文档对象模型）上执行预先制定好的逻辑。Thymeleaf的可扩展性也非常棒。
			你可以使用它定义自己的模板属性集合，这样就可以计算自定义表达式并使用自定义逻辑。这意味着Thymeleaf还可以作为模板引擎框架。
			Thymeleaf的模板还可以用作工作原型，Thymeleaf会在运行期替换掉静态值。例如下面的html文件，当作为静态文件时，product name显示为Red Chair，
			当运行在容器中并提供product这个对象时，product name的值会自动替换为product.description对应的值。 

			Thymeleaf是非常非常可扩展的，它允许自定义的名字来定义一组模板属性(或者甚至是标签)，用自定语法评估计算表达式和应用逻辑。它更像是一个模板引擎框架。
			它还带有一些称为标准方言(称为Standard和SpringStandard)的东西，它们定义了一组功能，这些功能应该足以满足大多数情况。
			可以识别这些标准方言在模板中的使用，因为它将包含以th前缀开头的属性，如<span th:text="...">。
			请注意，Standard和SpringStandard方言几乎完全相同，只是SpringStandard包含了集成到Spring MVC应用程序中的特定功能(例如，使用Spring表达式语言进行表达式评估而不是OGNL)。


    1) 导入启动器坐标 
			<dependency>
				<groupId>org.springframework.boot</groupId>
				<artifactId>spring-boot-starter-thymeleaf</artifactId>
			</dependency>
			
	  /*
		2) 配置视图解析	  //这段没做也可以
		（1）默认
				spring-boot很多配置都有默认配置,比如默认页面映射路径为
			    	classpath:/templates/星.html 
				同样静态文件路径为
						classpath:/static/
    （2）自定义
       在application.properties（或者application.yml）中可以配置thymeleaf模板解析器属性.就像使用springMVC的JSP解析器配置一样
			   spring.thymeleaf.mode=HTML5  //默认是 HTML5 ,如果想不是严格的HTML 可以用 LEGACYHTML5,但据说要导依赖  <groupId>net.sourceforge.nekohtml</groupId>  
																																																    						<artifactId>nekohtml</artifactId>  
																																																       					<version>1.9.22</version>  

			   spring.thymeleaf.encoding=UTF-8  //默认就是
			   spring.thymeleaf.content-type=text/html  //默认就是
			   #开发时关闭缓存,不然没法看到实时页面
			   spring.thymeleaf.cache=false  //这个默认是true
  
       具体可以配置的参数可以查看 org.springframework.boot.autoconfigure.thymeleaf.ThymeleafProperties 这个类,上面的配置实际上就是注入到该类中的属性值.
     */
   
	  3) 创建目录 src/main/resources/templates templates：该目录是安全的, 意味着该目录下的内容是不允许外界直接访问的
	      Thymeleaf 特点 是通过他特定语法对 html 的标记做渲染
	      
	      模板文件
				<!DOCTYPE html>
				<html>
				<head>
				<meta charset="UTF-8" >
				<title>Title</title>
				</head>
				<body>
	         <div th:text="helloworld"></div>   //一定要注意,败家贼米利夫, 这里不能写成 hello word, 或中间有什么符号,都不行
	         <span th:text="${msg}"></span>
				</body>
				</html>
	      
	      运行.出错:   //用最新版本的springroot发现没报相关的错
	       元素类型 "meta" 必须由匹配的结束标记 "</meta>" 终止。
	     
	      文档结构不标准,可以加上结束标签, 或使用高版本的 贼米利夫
					 <properties>
					   <thymeleaf.version>3.0.0.RELEASE</thymeleaf.version>
			   		 <thymeleaf-layout-dialect.version>2.0.0</thymeleaf-layout-dialect.version>
				  </properties>	  
				
				然后测就好使了,实测中发现   贼米利夫 居然和 tomcat的 org.apache.tomcat.embed 冲突,把tomcat关于jsp的那个注掉就可以了
			 
			  @RequestMapping("/testThymeleaf") 
				public String  testThymeleaf(Model m){
					m.addAttribute("msg","贼米利夫真垃圾");
					return "first";
				}
			
==== 1 Thymeleaf 语法之th属性
			 html有的属性，Thymeleaf基本都有，而常用的属性大概有七八个。其中th属性执行的优先级从1~8，数字越低优先级越高。
			一、th:text ：设置当前元素的文本内容，相同功能的还有th:utext，两者的区别在于前者不会转义html标签，后者会。优先级不高：order=7
			二、th:value：设置当前元素的value值，类似修改指定属性的还有th:src，th:href。优先级不高：order=6
			三、th:each：遍历循环元素，和th:text或th:value一起使用。注意该属性修饰的标签位置，详细往后看。优先级很高：order=2
			四、th:if：条件判断，类似的还有th:unless，th:switch，th:case。优先级较高：order=3
			五、th:insert：代码块引入，类似的还有th:replace，th:include，三者的区别较大，若使用不恰当会破坏html结构，常用于公共代码块提取的场景。优先级最高：order=1
			六、th:fragment：定义代码块，方便被th:insert引用。优先级最低：order=8
			七、th:object：声明变量，一般和*{}一起配合使用，达到偷懒的效果。优先级一般：order=4
			八、th:attr：修改任意属性，实际开发中用的较少，因为有丰富的其他th属性帮忙，类似的还有th:attrappend，th:attrprepend。优先级一般：order=5


			要注意:
			一、声明名称空间： xmlns:th="http://www.thymeleaf.org"
			二、th:each 的用法需要格外注意，打个比方：如果你要循环一个div中的p标签，则th:each属性必须放在p标签上。若你将th:each属性放在div上，则循环的是将整个div。		
			三、变量表达式中提供了很多的内置方法，该内置方法是用#开头，请不要与#{}消息表达式弄混。	
			四、th:insert，th:replace，th:include 三种插入代码块的效果相似，但区别很大。
			
		//例
			@Controller
			public class ThymeleafAction {
			    @RequestMapping("thymeleaf")
			    public String thymeleaf(ModelMap map) {
			    	System.out.println("--okk");
			        map.put("thText", "th:text 设置文本内容 <b>加粗也没用因为不会转义</b>");
			        map.put("thUText", "th:utext 设置文本内容 <b>加粗有用,会转义</b>");
			        map.put("thValue", "thValue 设置当前元素的value值");
			        map.put("thEach", Arrays.asList("香蕉", "芒果","桃子","杏","苹果"));
			        map.put("thIf", "msg is not null");
			        map.put("thObject", new UserInfo(99,"张悦","zhangyue123","这是备注"));
			        return "thymeleaf-pages/thymeleaf";
			    }
			}
		
		==== /resources /templates/thymeleaf-pages/thymeleaf.html
		<!DOCTYPE html>
		<html lang="en" xmlns:th="http://www.thymeleaf.org">   //好象是加上这个头以手,使用贼米利夫的标签就不报警告了
		  <head>
		    <meta charset="UTF-8">
		    <title>Thymeleaf 语法</title>
		  </head> 
		  <body>
		     //th:text 设置当前元素的文本内容，常用，优先级不高-
			    <p th:text="${thText}" />
			    <p th:utext="${thUText}" />
			    
			   //th:value 设置当前元素的value值，常用，优先级仅比th:text高
		      <input type="text" th:value="${thValue}" />
		      
		     //th:each 遍历列表，常用，优先级很高，仅次于代码块的插入
		     //th:each 修饰在div上，则div层重复出现，若只想p标签遍历，则修饰在p标签上
		     <div th:each="str : ${thEach}">
		        <p th:text="${str}" />
		     </div>
		     
		     //只遍历li，推荐使用
		     <ul> 
		        <li th:text="${str}" th:each="str:${thEach}" />
		     </ul>
		     
		    //th:if 条件判断，类似的有th:switch，th:case，优先级仅次于th:each, 其中#strings是变量表达式的内置方法
		    //如果 th:if 条件不成立,则这个 p 也画不出来
		    <p th:text="${thIf}" th:if="${not #strings.isEmpty(thIf)}"></p>
		     
		     
		    //th:object 声明变量，和*{} 一起使用
		    <div th:object="${thObject}">
		        <p> <span th:text="*{id}" /></p>      <!--th:text="${thObject.id}"-->
		        <p> <span th:text="*{userName}" /></p><!--${thObject.userName}-->
		        <p> <span th:text="*{password}" /></p><!--${thObject.password}-->
		        <p> <span th:text="*{note}" /></p>    <!--${thObject.note}-->
		    </div>
		    
		    //th:insert 把代码块插入当前div中，优先级最高，类似的有th:replace，th:include，~{} ：代码块表达式 
		    //common指的是 common.html 
		    //login-head是在common.html中声明的fragment
		    <div th:insert="~{thymeleaf-pages/common::login-head}"></div>
		    <div th:insert="~{thymeleaf-pages/common::#left}"></div>   //用id的方式引入,要这样写
		
  
		  </body>
		</html>

		附 thymeleaf-pages/common.html:
			<!DOCTYPE html>
			<html lang="en" xmlns:th="http://www.thymeleaf.org">
			<head>
			    <meta charset="UTF-8">
			    <title> </title>
			</head>
			  <body>   
			    <div th:fragment="login-head"  style="background:silver">
			        <span>这是给别人引入用的, 用的是 th:fragment </span>
			    </div>
			    
			    <p id="left" style="background:yellow">
			        <span>这是给别人引入的,用的是 id  </span>
			    </p>
			  </body>
			</html>
			
			
==== 3 Thymeleaf 语法 之常用的内置方法
			一、strings：字符串格式化方法，常用的Java方法它都有。比如：
					equals，equalsIgnoreCase，length，trim，toUpperCase，toLowerCase，indexOf，substring，replace，startsWith，endsWith，contains，containsIgnoreCase等
			
			二、numbers：数值格式化方法，常用的方法有：formatDecimal等			
			三、bools：布尔方法，常用的方法有：isTrue，isFalse等	
			四、arrays：数组方法，常用的方法有：toArray，length，isEmpty，contains，containsAll等
			五、lists，sets：集合方法，常用的方法有：toList，size，isEmpty，contains，containsAll，sort等
			六、maps：对象方法，常用的方法有：size，isEmpty，containsKey，containsValue等
			七、dates：日期方法，常用的方法有：format，year，month，hour，createNow等

		//例 varexpression 
		    @RequestMapping("varexpressions")
		    public String varexpressions(ModelMap map) {
		        map.put("xxxStr", "this is a cat");
		        map.put("xxxBool", false);
		        map.put("xxxArray", new Integer[]{1,2,3,4});
		        map.put("xxxList", Arrays.asList(1,3,2,4,0));
		        
		        Map xxxMap = new HashMap();
		        xxxMap.put("第一", "陈聪");
		        xxxMap.put("第二", "范鸽");
		        map.put("xxxMap", xxxMap);
		        
		        map.put("xxxDate", new Date());
		        map.put("xxxNum", 888.888D);
		        return "thymeleaf-pages/varexpressions";
		    }
    
		==== /resources /templates/thymeleaf-pages/varexpressions.html
			<!DOCTYPE html>
			<html lang="en" xmlns:th="http://www.thymeleaf.org">
			<head>
			    <meta charset="UTF-8">
			    <title> 内置方法</title>
			</head>
			<body>
			      //string
			 		 <div th:if="${not #strings.isEmpty(xxxStr)}" >
				        <p>Old Str : <span th:text="${itdragonStr}"/></p>
				        <p>toUpperCase : <span th:text="${#strings.toUpperCase(xxxStr)}"/></p>
				        <p>toLowerCase : <span th:text="${#strings.toLowerCase(xxxStr)}"/></p>
				        <p>equals : <span th:text="${#strings.equals(xxxStr, 'this is a cat')}"/></p>
				        <p>equalsIgnoreCase : <span th:text="${#strings.equalsIgnoreCase(xxxStr, 'this is A cat')}"/></p>
					 			<p>indexOf : <span th:text="${#strings.indexOf(xxxStr, 'r')}"/></p>
				        <p>substring : <span th:text="${#strings.substring(xxxStr, 2, 8)}"/></p>
				        <p>replace : <span th:text="${#strings.replace(xxxStr, 'is', 'dddd')}"/></p>
				        <p>startsWith : <span th:text="${#strings.startsWith(xxxStr, 'it')}"/></p>
				        <p>contains : <span th:text="${#strings.contains(xxxStr, 'IT')}"/></p>
				   </div>
				    
				    //number
		        <div>
			        <p>formatDecimal 整数部分随意，小数点后保留两位，四舍五入: <span th:text="${#numbers.formatDecimal(xxxNum, 0, 2)}"/></p>  888.89
			        <p>formatDecimal 整数部分保留五位数，小数点后保留两位，四舍五入: <span th:text="${#numbers.formatDecimal(xxxNum, 5, 2)}"/></p> 00888.89
		        </div>
			        
			      //boolean
			      <div th:if="${#bools.isTrue(xxxBool)}">
			      		 这是true
			   		</div>
			      <div th:unless="${#bools.isTrue(xxxBool)}">
			      		  这是false
			   		</div>
			    
				    //#arrays
				    <div th:if="${not #arrays.isEmpty(xxxArray)}">
				        <p>length : <span th:text="${#arrays.length(xxxArray)}"/></p>
				        <p>contains : <span th:text="${#arrays.contains(xxxArray, 4)}"/></p>
				        <p>containsAll : <span th:text="${#arrays.containsAll(xxxArray, xxxArray)}"/></p>
				    </div>
				    
				    //#lists 
				    <div th:if="${not #lists.isEmpty(xxxList)}">
				        <p>size : <span th:text="${#lists.size(xxxList)}"/></p>
				        <p>contains : <span th:text="${#lists.contains(xxxList, 0)}"/></p>
				        <p>sort : <span th:text="${#lists.sort(xxxList)}"/></p>
				    </div>
				    
				    //#maps 
				    <div th:if="${not #maps.isEmpty(xxxMap)}">
				        <p>size : <span th:text="${#maps.size(xxxMap)}"/></p>
				        <p>containsKey : <span th:text="${#maps.containsKey(xxxMap, '第一')}" /></p>
				        <p>containsValue : <span th:text="${#maps.containsValue(xxxMap, '陈聪')}" /></p>
				    </div>
			    
				    //#dates
				    <div>
				        <p>format : <span th:text="${#dates.format(xxxDate)}"/></p> //Septhemba 29, 2019 2:04:48 PM CST
				        <p>custom format : <span th:text="${#dates.format(xxxDate, 'yyyy-MM-dd HH:mm:ss')}"/></p>
				        <p>day : <span th:text="${#dates.day(xxxDate)}"/></p>
				        <p>month : <span th:text="${#dates.month(xxxDate)}"/></p>
				        <p>monthName : <span th:text="${#dates.monthName(xxxDate)}"/></p>  //Septhemba
				        <p>year : <span th:text="${#dates.year(xxxDate)}"/></p>
				        <p>dayOfWeekName : <span th:text="${#dates.dayOfWeekName(xxxDate)}"/></p>  //ISonto
				        <p>hour : <span th:text="${#dates.hour(xxxDate)}"/></p>
				        <p>minute : <span th:text="${#dates.minute(xxxDate)}"/></p>
				        <p>second : <span th:text="${#dates.second(xxxDate)}"/></p>
				        <p>createNow : <span th:text="${#dates.createNow()}"/></p>
				    </div>   
			 </body>
			
			</html>
			
			   
==== 3 Thymeleaf 语法 之标准表达式语法
				有五种类型:
				1)	${...} : 变量表达式。
				2)	*{...} : 选择表达式。
				3)	#{...} : 消息 (i18n) 表达式。
				4)	@{...} : 链接 (URL) 表达式。
				5)	~{...} : 片段表达式。

				1)	${...} : 变量表达式 
				变量表达式有丰富的内置方法，使其更强大，更方便。
					一、可以获取对象的属性和方法
					二、可以使用ctx，vars，locale，request，response，session，servletContext内置对象
					三、可以使用dates，numbers，strings，objects，arrays，lists，sets，maps等内置方法（重点介绍）
					
					常用的内置对象
					一、ctx ：上下文对象。
					二、vars ：上下文变量。
					三、locale：上下文的语言环境。
					四、request：（仅在web上下文）的 HttpServletRequest 对象。
					五、response：（仅在web上下文）的 HttpServletResponse 对象。
					六、session：（仅在web上下文）的 HttpSession 对象。
					七、servletContext：（仅在web上下文）的 ServletContext 对象
					
					 变量表达式是OGNL表达式 - 如果将Thymeleaf 与Spring - 集成在上下文变量上(也称为Spring术语中的模型属性)，则为Spring EL。 它们看起来像这样:
					    
					  === ${session.user.name}
					  === <span th:text="${book.author.name}">  在OGNL和SpringEL中 ==>((Book)context.getVariable("book")).getAuthor().getName()   
					  === <li th:each="book : ${books}">
					
					   //例
						  @RequestMapping("/testThymeleaf2") 
							public String  testThymeleaf2(Model m,HttpSession session){
								UserInfo user=new UserInfo(1,"赵强","小明","备注");
								m.addAttribute("user",user);
								session.setAttribute("admin", user);
								return "second";
							}
							
						 second.html 中
		         <div th:text="${session.admin.userName}"></div>
		         <div th:text="${user.userName}"></div>
	         
	       2) *{...} : 选择表达式。
							  <div th:object="${session.admin}">
									<h1 th:text="*{userName}" ></h1> 
									<h1 th:text="*{password}" ></h1>
								</div>
									
								<p th:object="${user}">
									<input th:value="*{userName}" >
								</p>
								
				3)	#{...} : 消息 (i18n) 表达式。
				     消息表达式,一般用于国际化场景
						 在Spring应用程序中，它将自动与Spring的MessageSource机制集成。如下 - 
								
							th:text="#{msg}"
				
				4)	@{...} : 链接 (URL) 表达式。
						 不管是静态资源的引用，form表单的请求，凡是链接都可以用@{...} 。这样可以动态获取项目路径，即便项目名变了，依然可以正常访问
						 #修改项目名，链接表达式会自动修改路径，避免资源文件找不到
					  	server.context-path=/itdragon
					  	
					  	链接表达式结构

							无参：@{/xxx}
							
							有参：@{/xxx(k1=v1,k2=v2)} 对应url结构：xxx?k1=v1&k2=v2
							
							引入本地资源：@{/项目本地的资源路径}
							
							引入外部资源：@{/webjars/资源在jar包中的路径}

								<link th:href="@{/webjars/bootstrap/4.0.0/css/bootstrap.css}" rel="stylesheet">
								<link th:href="@{/main/css/itdragon.css}" rel="stylesheet">
								<form class="form-login" th:action="@{/user/login}" th:method="post" >
								<a class="btn btn-sm" th:href="@{/login.html(l='zh_CN')}">中文</a>
								<a class="btn btn-sm" th:href="@{/login.html(l='en_US')}">English</a>

						
					   用来配合link src href使用的语法，类似的标签有 th:href 和 th:src   
					   <a href="details.html" th:href="@{http://localhost:8080/order/details(orderId=${order.id})}">订单详细</a> 
					        ==>翻译成:  <a href="http://localhost:8080/order/details?orderId=99">订单详细</a> 
						
							<a href="details.html" th:href="@{/order/details(orderId=${order.id})}">订单详细</a>
						   	  ==>翻译成: a href="/order/details?orderId=99">订单详细</a>
						   	  
							<a href="details.html" th:href="@{goods/}+${order.id}">订单详细</a>	
									==>翻译成: <a href="goods/99">订单详细</a>  
	                         
        5)	~{...} : 片段表达式。
            支持两种结构:
						推荐：~{templatename::fragmentname}
						支持：~{templatename::#id}
						
							templatename：模版名，Thymeleaf会根据模版名解析完整路径：/resources/templates/templatename.html，要注意文件的路径。
							
							fragmentname：片段名，Thymeleaf通过th:fragment声明定义代码块，即：th:fragment="fragmentname"
							
							id：HTML的id选择器，使用时要在前面加上#号，不支持class选择器。
							
							代码块表达式的使用
							
							代码块表达式需要配合th属性（th:insert，th:replace，th:include）一起使用
								th:insert：将代码块片段整个插入到使用了th:insert的HTML标签中，
								th:replace：将代码块片段整个替换使用了th:replace的HTML标签中，
								th:include：将代码块片段包含的内容插入到使用了th:include的HTML标签中，
								

								<!--th:fragment定义代码块标识-->
								<footer th:fragment="copy">
									  内容
								</footer>
								
								//三种不同的引入方式
								<div th:insert="footer :: copy"></div>
								<div th:replace="footer :: copy"></div>
								<div th:include="footer :: copy"></div>
								
								//th:insert是在div中插入代码块，即多了一层div
								<div>
								    <footer>
								   		  内容
								    </footer>
								</div>
								
								//th:replace是将代码块代替当前div，其html结构和之前一致
								<footer>
									 内容
								</footer>
								
								//th:include是将代码块footer的内容插入到div中，即少了一层footer
								<div>
										 内容
								</div>
								
							实例: commons.html 
						    <footer th:fragment="copy">
							   		 <div style="width:500px;height:100px;background:pink" >
												黑龙江省海康软件
											</div>
								</footer>
								
							引入:
							 <div th:include="~{thymeleaf-pages/common::copy}"></div>
							 
==== 4 Thymeleaf在SpringBoot应用
		Thymeleaf是Spring Boot 官方推荐使用的模版引擎，这也意味着用Thymeleaf比其他模版引擎更简单。
			
			开发步骤：
			第一步：引入Thymeleaf依赖。
			第二步： 提取公共页面，提高代码的重用性，统一页面风格。
			第三步：页面显示和国际化功能

	  1) 引入Thymeleaf依赖。
					pom.xml 引入Thymeleaf的依赖，并确定其版本
					<properties>
					  <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
					  <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
					  <java.version>1.8</java.version>
					  <thymeleaf.version>3.0.9.RELEASE</thymeleaf.version>
					  <thymeleaf-layout-dialect.version>2.2.2</thymeleaf-layout-dialect.version>
					</properties>
					
					<dependencies>
					  <dependency> <!--引入模版引擎thymeleaf-->
					    <groupId>org.springframework.boot</groupId>
					    <artifactId>spring-boot-starter-thymeleaf</artifactId>
					  </dependency>
					</dependencies>

	   	2) 提取公共页面，提高代码的重用性，统一页面风格。前面介绍了SiteMesh的使用，今天用Thymeleaf来实现。
						
					(1) 统一规范引入的资源文件 
						
						/resoruce/templates/commons/default.html
						<!DOCTYPE html>
						<html lang="en" xmlns:th="http://www.thymeleaf.org">
						    <head th:fragment="common-head">
						        <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
						        <meta name="viewport" content="initial-scale=1.0, width=device-width, user-scalable=no" />
						        <title>ITDragon系统</title>
						        <link type="image/x-icon" href="images/favicon.ico" rel="shortcut icon">   //浏览器器上面的小图标
						        <link th:href="@{/sb-admin-1.0.4/css/bootstrap.min.css}" rel="stylesheet">
						        <link th:href="@{/sb-admin-1.0.4/css/sb-admin.css}" rel="stylesheet">
						        <link th:href="@{/sb-admin-1.0.4/css/plugins/morris.css}" rel="stylesheet">  //和图表插件有关
						        <link th:href="@{/sb-admin-1.0.4/font-awesome/css/font-awesome.min.css}" rel="stylesheet">
						        <script th:src="@{/sb-admin-1.0.4/js/jquery.js}"></script>
						        <script th:src="@{/sb-admin-1.0.4/js/bootstrap.min.js}"></script>
						        <script th:src="@{/sb-admin-1.0.4/js/plugins/morris/raphael.min.js}"></script> //和图表插件有关
						        <script th:src="@{/sb-admin-1.0.4/js/plugins/morris/morris.min.js}"></script>  //和图表插件有关
						        <script th:src="@{/sb-admin-1.0.4/js/plugins/morris/morris-data.js}"></script> //和图表插件有关
						    </head>
						</html>
 
				 (2) 统一左侧菜单栏
						 /resoruce/templates/commons/header.html
							<!DOCTYPE html>
							<html lang="en" xmlns:th="http://www.thymeleaf.org">
							<head>
							    <meta charset="UTF-8">
							</head>
							<body>
							<header id="header" th:fragment="common-header">
							    <!-- Navigation -->
							    <nav class="navbar navbar-inverse navbar-fixed-top" role="navigation">
							        <!-- Brand and toggle get grouped for better mobile display -->
							        <div class="navbar-header">
							            <button type="button" class="navbar-toggle" data-toggle="collapse" data-target=".navbar-ex1-collapse">
							                <span class="sr-only">Toggle navigation</span>
							                <span class="icon-bar"></span>
							                <span class="icon-bar"></span>
							                <span class="icon-bar"></span>
							            </button>
							            <a class="navbar-brand" th:href="@{/main}">Thymeleaf 演示系统  0.0.1</a>
							        </div>
							        <!-- Top Menu Items -->
							        <ul class="nav navbar-right top-nav">
							            <li class="dropdown">
							                <a href="#" class="dropdown-toggle" data-toggle="dropdown"><i class="fa fa-envelope"></i> <b class="caret"></b></a>
							                <ul class="dropdown-menu message-dropdown">
							                    <li class="message-preview">
							                        <a href="#">
							                            <div class="media">
							                                <span class="pull-left">
							                                    <img class="media-object" src="http://placehold.it/50x50" alt="">
							                                </span>
							                                <div class="media-body">
							                                    <h5 class="media-heading"><strong>栗梦真</strong>
							                                    </h5>
							                                    <p class="small text-muted"><i class="fa fa-clock-o"></i> Yesterday at 4:32 PM</p>
							                                    <p>这里是一些想显示出来的字什么的...</p>
							                                </div>
							                            </div>
							                        </a>
							                    </li>
							                    <li class="message-footer">
							                        <a href="#">Read All New Messages</a>
							                    </li>
							                </ul>
							            </li>
							            <li class="dropdown">
							                <a href="#" class="dropdown-toggle" data-toggle="dropdown"><i class="fa fa-bell"></i> <b class="caret"></b></a>
							                <ul class="dropdown-menu alert-dropdown">
							                    <li>
							                        <a href="#">primary message...<span class="label label-primary">99+</span></a>
							                    </li>
							                    <li>
							                        <a href="#">success message...<span class="label label-success">10</span></a>
							                    </li>
							                    <li>
							                        <a href="#">danger message...<span class="label label-danger">6</span></a>
							                    </li>
							                    <li class="divider"></li>
							                    <li>
							                        <a href="#">View All</a>
							                    </li>
							                </ul>
							            </li>
							            <li class="dropdown">
							                <a href="#" class="dropdown-toggle" data-toggle="dropdown"><i class="fa fa-user"></i> <b class="caret"></b></a>
							                <ul class="dropdown-menu">
							                    <li>
							                        <a href="#"><i class="fa fa-fw fa-user"></i> Profile</a>
							                    </li>
							                    <li>
							                        <a href="#"><i class="fa fa-fw fa-gear"></i> Settings</a>
							                    </li>
							                    <li class="divider"></li>
							                    <li>
							                        <a href="/logout"><i class="fa fa-fw fa-power-off"></i> Log Out</a>
							                    </li>
							                </ul>
							            </li>
							            <li class="dropdown">
							                <a href="#" class="dropdown-toggle" data-toggle="dropdown"><i class="fa fa-globe"></i> <b class="caret"></b></a>
							                <ul class="dropdown-menu">
							                    <li>
							                        <a th:href="@{/employees(l='zh_CN')}">中文</a>
							                    </li>
							                    <li>
							                        <a th:href="@{/employees(l='en_US')}">English</a>
							                    </li>
							                </ul>
							            </li>
							        </ul>
							        <!-- Sidebar Menu Items - These collapse to the responsive navigation menu on small screens -->
							        <div class="collapse navbar-collapse navbar-ex1-collapse">
							            <ul class="nav navbar-nav side-nav itdragon-nav">
							                <li th:class="${activeUrl=='dashboard'?'nav-link active':'nav-link'}">
							                    <a th:href="@{/main}"><i class="fa fa-fw fa-dashboard"></i> 系统首页</a>
							                </li>
							                <li th:class="${activeUrl=='employees'?'nav-link active':'nav-link'}">
							                    <a th:href="@{/users}"><i class="fa fa-fw fa-bar-chart-o"></i> 用户管理</a>
							                </li>
							                <li>
							                    <a th:href="@{/thymeleaf}" ><i class="fa fa-fw fa-table"></i>常用th属性</a>
							                </li>
							                <li>
							                    <a  th:href="@{/varexpressions}" ><i class="fa fa-fw fa-file"></i>内置方法</a>
							                </li>
							            </ul>
							        </div>
							        <!-- /.navbar-collapse -->
							    </nav>
							</header>
							</body>
							</html>
			
						以上代码用到了三个知识点：		
						一、使用链接表达式引入本地的资源文件，若引入第三方外部资源文件，可以通过webjars（将资源文件打成jar包放在项目中）方式引入。
						二、使用th:fragment标识需要被引用的代码块，也可以用id选择器但不推荐。
						三、activeUrl变量是通过代码块表达式在其他页面传入的变量，这也是代码块表达式强大的一个功能。


		    (3)	页面显示和信息从配置文件读取
		        == 准备资源文件
		           resources/i18n/sys.properties 
									id=用户ID
									userName=用户名
									password=密码
									gender=性别
									note=备注
									birthday=出生日期
									operation=操作
									add.user=添加用户
									
		        == 在 resources/application.properties 指定引入
		        	  spring.thymeleaf.cache=false
		        		spring.messages.basename=i18n.sys
		        
		        == 在页面使用消息表达式输出
		            例如: 	<th th:text="#{userName}"></th>
		         

							<!DOCTYPE html>
							<html lang="en" xmlns:th="http://www.thymeleaf.org">
							<head th:replace="~{commons/public::common-public}">
								<meta name="viewport" content="initial-scale=1.0, width=device-width, user-scalable=no" />
								<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
								<meta http-equiv="X-UA-Compatible" content="IE=edge,Chrome=1" />
								<meta http-equiv="X-UA-Compatible" content="IE=8" />
								<title>员工列表</title>
							</head>
							<body>
							<div id="wrapper">
								<header th:replace="~{commons/header::common-header(activeUrl='users')}"></header>
								<div id="page-wrapper">
									<div class="container-fluid">
										<!-- Page Heading -->
										<div class="row">
											<div class="col-lg-12">
												<h1 class="page-header" th:text="用户管理"></h1>
												<ol class="breadcrumb">
													<li><i class="fa fa-dashboard"></i> <a href="main" th:text="系统主页"></a>
													</li>
													<li class="active"><i class="fa fa-table"></i> <span th:text="用户列表"></span></li>
												</ol>
											</div>
										</div>
										<div class="row" th:if="${not #strings.isEmpty(message)}">
											<div class="col-lg-12">
												<div class="alert alert-info alert-dismissable">
													<button type="button" class="close" data-dismiss="alert" aria-hidden="true">&times;</button>
													<i class="fa fa-info-circle"></i> <strong th:text="${message}"></strong>
												</div>
											</div>
										</div>
										<!-- /.row -->
										<div class="row">
											<div class="col-lg-12">
												<h2 th:text="用户列表"></h2>
												<div class="table-responsive">
													<a class="pull-right btn" th:href="@{/employee}" th:text="#{add.user}"></a>
													<table class="table table-striped table-sm">
														<thead>
														<tr>
														  //下面这些表的标题,都是从资源文件中提取的
															<th th:text="#{id}"></th>
															<th th:text="#{userName}"></th>
															<th th:text="#{password}"></th>
															<th th:text="#{gender}"></th>
															<th th:text="#{note}"></th>
															<th th:text="#{birthday}"></th>
															<th th:text="#{operation}"></th>
														</tr>
														</thead>
														<tbody>
														<tr th:each="u:${usersList}">
															<td th:text="${u.id}"></td>
															<td th:text="${u.userName}"></td>
															<td th:text="${u.password}"></td>
															<td th:text="${u.gender}==0?'女':'男'"></td>
															<td th:text="${u.note}"></td>
															<td th:text="${#dates.format(u.birthday, 'yyyy-MM-dd HH:mm')}"></td>
															<td>
																<a class="btn btn-sm btn-success" th:href="@{/user/}+${u.id}" th:text="修改"></a>
																<a class="btn btn-sm btn-danger deleteBtn" th:href="@{/user/}+${u.id}" th:text="删除"></a>
															</td>
														</tr>
														</tbody>
													</table>
												</div>
											</div>
										</div>
										<!-- /.row -->
									</div>
								</div>
							</div>
							</body>
							</html>
					
					  以上代码用到了知识点：		
						一、页面通过代码块表达式引入公共代码块，并传入参数给公共代码块文件。
						二、页面使用消息表达式输出国际化内容。	
						三、使用th:if属性条件判断，使用内置方法#strings.isEmpty 判断参数是否为空，使用内置方法#dates.format 格式化参数
						四、使用th:each属性循环遍历，注意该属性修改在tr标签上。并使用th:text属性给td标签赋值

==== 6 增删改查
     请参见 springboot-demo3-theymeleaf 项目
     
			@Controller
			public class UserAction {
				@Resource
				private UserDao userDao;
			
				//查询所有用户列表
				@GetMapping("/users")
				public String findAll(ModelMap map) {
					
					map.put("usersList", userDao.getUserList());
					return "user-pages/user-manager";
				}
				
				//转到用户添加界面
				@GetMapping("/user")
			    public String toAddPage(){
			        return "user-pages/user-add";
			    }
				
				//真正的进行用户添加,实际上用户修改走的也是这个方法,内部会根据有没有id进行区分
				@PostMapping("/user")
			    public String addUser(UserInfo user){
					userDao.save(user);
			        return "redirect:/users";
			    }
				
				//来到修改页面，查出当前用户，在页面回显
			    @GetMapping("/user/{id}")
			    public String toEditPage(@PathVariable("id") Integer id, Model model){
			        UserInfo user = userDao.getUserById(id);
			        model.addAttribute("user", user);
			        //回到修改页面(user-add是一个修改添加二合一的页面);
			        return "user-pages/user-add";
			    }
			    
			    @GetMapping("/delete/{id}")
			    public String deleteUser(@PathVariable("id") Integer id){
			        userDao.deleteUserById(id);
			        return "redirect:/users";
			    }
			    
			    /* 下面的两种方式,实测无效
			    //用户修改；需要提交员工id,实测发现,这个方法PutMapping ,可能是因为tomcat8不能识别put请求
			    @PutMapping("/user")
			    public String updateUser(UserInfo user){
			    	userDao.save(user);
			        return "redirect:/users";
			    }
			    
			    //用户删除
			    @DeleteMapping("/user/{id}")
			    public String deleteUser(@PathVariable("id") Integer id){
			        userDao.deleteUserById(id);
			        return "redirect:/users";
			    }
			    */
			}

      附 application.properties:
        
				spring.thymeleaf.cache=false
				spring.messages.basename=i18n.sys
				spring.mvc.date-format=yyyy-MM-dd
				
		  附
				Spring Boot 实现国际化步骤：
				第一步：准备好国际化文件，至少三分（系统默认，中文，英文）
				第二步：在Spring Boot全局配置文件中，指定国际化文件路径，
				第三步：自定义Locale Resolver
				第四步：在页面上使用消息表达式输出国际化内容